package com.example.utils;

import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.support.v4.app.NotificationCompat;

/**
 * 
 * For a complete design and coding guide to status bar notifications, refer to the following: 
 * <p>
 * {@link http://developer.android.com/guide/topics/ui/notifiers/notifications.html}
 * {@link http://developer.android.com/reference/android/support/v4/app/NotificationCompat.Builder.html}
 * <p>
 * This class contains a host of static functions that are useful for making, managing, and posting
 * local notifications on the status bar. The functions used here are compatible for Android 4-16
 * <p>
 * This class is not meant to be extended or instantiated.
 * <p>
 * The flowchart of making a notification in Android using this class is as follows:
 * <p>
 * PendingIntent clickHandler = makeNotifHandler();
 * Notification notif = makeNotification(clickHandler, other params..);
 * broadcastNotification(integer id, notif);
 * <p>
 * 
 * The first line of the code defines the behavior of the notification when it has been tapped or clicked.
 * Specifically, the click will launch one of the application's activity to handle it, such as displaying the
 * detailed view of a particular notification.
 * <p>
 * The second line generates the notification, using the response handler from the first line.
 * <p>
 * The third line asks the Notification Manager, which is a service in the application framework to
 * post the notification.
 * <p>
 * 
 * By convention, notifications with...
 * <p>
 *  	-Negative IDs are for special collapse-able notifications that should only be displayed once.
 *  <p> 
 *  	-Positive IDs are for individual notifications, where each notification will be displayed 
 *  	individually in the status bar.
 *  <p>
 * Sample function call for a plain text notification that is not collapse-able:
 * <p>
 * 		PendingIntent noActIntent = NotificationFunctions.makeNotifHandlerNoAction(context);
 * <p>
 *			Notification notif = NotificationFunctions.makeNotification(context,
 *					noActIntent,
 *					"New Message",
 *					System.currentTimeMillis(),
 *					"App_name",
 *					"Message Content",
 *					R.drawable.ic_notify);
 *<p>
 *			NotificationFunctions.broadcastNotification(0, context, notif);
 * <p>
 * The above code block generates a status bar notification 
 * <p>
 * 
 * Sample function calls for a notification that starts the app's main activity upon being clicked:
 * <p>
 * 		PendingIntent noActIntent = NotificationFunctions.makeNotifHandler(context, 
 * 				MainAct.class, 
 * 				new Bundle());
 * <p>
 *			Notification notif = NotificationFunctions.makeNotification(context,
 *					noActIntent,
 *					"New Message",
 *					System.currentTimeMillis(),
 *					"App_name",
 *					"Message Content",
 *					R.drawable.ic_notify);
 *<p>
 *			NotificationFunctions.broadcastNotification(-1, context, notif);
 *<p>
 *
 * It is highly encouraged for one to write additional functions to accommodate for any other
 * notification needs. 
 *
 */
public final class NotificationFunctions {
	
	private static final int INDIVIDUAL_ID = 0;
	private static int INDIVIDUAL_NOTIFY = 0;
	
	/**
	 * Creates a notification that launches a relevant activity when it is clicked.
	 * 
	 * @param appContext The application's Context.
	 * @param handlerAct The activity that'll be started when the notification is clicked.
	 * @param activityData A map of Parcelable data to be imported into the activity.
	 * @returnThe handler for the notification to respond to being clicked.
	 */
	public static PendingIntent makeNotifHandler(Context appContext, Class<?> handlerAct, Bundle activityData) {
		Intent notifyIntent = new Intent(appContext, handlerAct);
		notifyIntent.putExtras(activityData);
		PendingIntent contentIntent = PendingIntent.getActivity(appContext, 0, notifyIntent, 0);
		
		return contentIntent;
	}
	
	/**
	 * Creates a notification that performs no action when it is clicked.
	 * 
	 * @param appContext The application's Context
	 * @return The handler for the notification to respond to being clicked.
	 */
	public static PendingIntent makeNotifHandlerNoAction(Context appContext) {
		Intent notifyIntent = new Intent();
		PendingIntent contentIntent = PendingIntent.getActivity(appContext, 0, notifyIntent, 0);
		return contentIntent;
	}
	
	/**
	 * Generates a notification suitable to be broadcasted by the notification manager.
	 * @param appContext The application's context.
	 * @param notifHandler The intent that starts an activity, when the notification is clicked.
	 * @param tickerText The text to display in the notification bar when it flashes.
	 * @param when The time the notification is made, in seconds after 1/1/1970
	 * @param title The notification's title.
	 * @param text The notification's text.
	 * @param icon An integer referring to the icon resource in the project.
	 * @return The notification object.
	 */
	public static Notification makeNotification(
			Context appContext,
			PendingIntent notifHandler,
			String tickerText,
			long when,
			String title,
			String text,
			int icon
			) {
		NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(appContext);
		notificationBuilder = notificationBuilder.setContentIntent(notifHandler); //Launch the activity specified by the intent when clicked.
		notificationBuilder = notificationBuilder.setTicker(tickerText); //The small text that appears when a new notification is here
		notificationBuilder = notificationBuilder.setWhen(when); //Set the time that the notification occurred
		notificationBuilder = notificationBuilder.setAutoCancel(true); //Automatically delete this notification after being clicked
		notificationBuilder = notificationBuilder.setContentTitle(title); //Set the notification's title
		notificationBuilder = notificationBuilder.setContentText(text); //Set the text/message
		notificationBuilder = notificationBuilder.setSmallIcon(icon); //Use an icon. (Mandatory)
		Notification notification = notificationBuilder.build(); //Build it
		return notification;
	}
	/**
	 * This function will call the notification manager of the application to display a notification
	 * in the status bar, given a notification object.
	 * <p>
	 * It is a modified version of the notification manager's default notify function. Refer to the Javadoc
	 * of NotificationManager.notify() {@link NotificationManager}
	 * <p>
	 * This modification does not currently support vibrating, LED or backlight flashing, and sounds.
	 * It's main purpose is to simplify the process of creating a notification as well as organizing it.
	 * 
	 * @param notify_id The ID of the notification. The behavior depends on the ID called:
	 * 				<p>
	 * 				If a specific, negative integer is used, then the notification will overwrite the
	 * 					previous notification with the same ID.
	 * 				<p> 
	 * 				If a positive integer is supplied, then each individual notification will be
	 * 					posted in the status bar.
	 * @param appContext The application context.
	 * @param notification The notification object created using makeNotification()
	 */
	public static void broadcastNotification(int notify_id, Context appContext, Notification notification) {
		NotificationManager notificationManager = (NotificationManager) 
				appContext.getSystemService(Context.NOTIFICATION_SERVICE);
		//This is an individual notification. (Positive integer)
		if (notify_id >= INDIVIDUAL_ID) {
			notificationManager.notify(INDIVIDUAL_NOTIFY++, notification);
			//The app has been running for a long time, and there has been a lot of individual notifications.
			//Reset the counter so it doesn't go into the negative values due to overflow.
			if (Integer.MAX_VALUE - INDIVIDUAL_NOTIFY  < 10) {
				INDIVIDUAL_NOTIFY = 0;
			}
		}
		//Overwrite the previous notification of the same category. (Negative integer)
		else {
			notificationManager.notify(notify_id, notification);
		}		
	}
}
